//! # State - 状态管理模块
//!
//! 核心 State： [`AppState`]

pub mod player_state;

use std::{collections::HashMap, path::PathBuf, sync::Arc};

use rand::Rng;
use tokio::sync::RwLock;

use crate::config::mapper::MapperConfig;

use self::player_state::PlayerState;

/// Player ID
type ID = usize;

/// 应用状态
#[derive(Default)]
pub struct AppState<'a> {
    /// 播放器
    pub players: Arc<RwLock<HashMap<ID, PlayerState<'a>>>>,
}

impl<'a> AppState<'a> {
    /// 生成一个新的播放器对象
    ///
    /// # 参数
    ///
    /// * `mapper` - 映射器
    /// * `path` - Midi 文件路径
    ///
    /// # 返回值
    ///
    /// * [`Ok(String)`] - 播放器 ID
    /// * [`Err(String)`] - 错误信息
    ///
    /// # 示例
    ///
    /// ```
    /// let id = state.new_player(mapper, path).await.unwrap();
    /// ```
    pub async fn new_player(&self, mapper: MapperConfig, path: PathBuf) -> Result<String, String> {
        loop {
            // 随机生成 ID
            let id: ID = rand::thread_rng().gen();

            // 直到找到一个没有被占用的 ID
            if !self.players.read().await.contains_key(&id) {
                // 记录日志
                log::info!("生成新的 {} 播放器 ID = {id}", mapper.name);

                // 生成一个播放器
                self.players
                    .write()
                    .await
                    .insert(id, PlayerState::new(&mapper, path)?);

                // 返回 ID
                return Ok(id.to_string());
            }
        }
    }

    /// 解析并检查 ID
    ///
    /// # 参数
    ///
    /// * `id` - ID
    ///
    /// # 返回值
    ///
    /// * [`Ok(ID)`] - ID
    /// * [`Err(String)`] - 错误信息
    ///
    /// # 示例
    ///
    /// ```
    /// let id = state.parse_and_check_id("1").await.unwrap();
    /// ```
    pub async fn parse_and_check_id(&self, id: &str) -> Result<ID, String> {
        // 记录日志
        log::debug!("解析并检查 ID = {id}");

        // 解析 ID
        let id: ID = id
            .parse()
            .map_err(|_| format!("输入的 ID = {id} 不是整数"))?;

        // 检查 ID
        if self.players.read().await.contains_key(&id) {
            Ok(id)
        } else {
            Err(format!("没有 ID = {id} 的播放器"))
        }
    }
}
